package io.gitee.hejiang.action.impl;

import java.sql.Connection;
import java.util.Map;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;

import com.fasterxml.jackson.databind.JavaType;

import io.gitee.hejiang.action.SwaggerSqlAction;
import io.gitee.hejiang.action.SwaggerSqlActionProvider;
import io.swagger.inflector.models.RequestContext;

public class ExpressionActionProvider implements SwaggerSqlActionProvider {

	@Override
	public SwaggerSqlAction createAction(Map<String, Object> config) {
		String type = (String) config.get("type");
		if ("expr".equalsIgnoreCase(type) || config.containsKey("expr") ||
				"expression".equalsIgnoreCase(type) || config.containsKey("expression")) {
			return new SwaggerSqlActionImpl();
		}
		return null;
	}

	static ScriptableObject sharedScope;
	static {
		Context cx = Context.enter();

		sharedScope = cx.initStandardObjects(null, true);
		// Force the LiveConnect stuff to be loaded.
		String loadMe = "RegExp; getClass; java; Packages; JavaAdapter;";
		cx.evaluateString(sharedScope, loadMe, "lazyLoad", 0, null);
		sharedScope.sealObject();

		Context.exit();
	}

	public class SwaggerSqlActionImpl implements SwaggerSqlAction {
		SwaggerSqlAction _next;
		String _expr, _key;
		Map<String, Object> _config;

		@Override
		public void init(Map<String, Object> config, Map<String, JavaType> argumentTypes, SwaggerSqlAction next)
				throws Exception {
			_next = next;
			_key = (String) config.get("key");
			if (_key == null) {
				_key = "ans";
			}

			_config = config;
			_expr = (String) config.get("expr");
			if (_expr == null) {
				throw new Exception("Please assign expr.");
			}
		}

		@Override
		public Object execute(RequestContext request, Connection connection, Map<String, Object> arguments,
				Map<String, Object> context) throws Exception {
			Object ret = null;
			Context cx = Context.enter();
			cx.setWrapFactory(ObjectWrapFactory.instance());
			try {
				Scriptable scope = cx.newObject(sharedScope);
				scope.setPrototype(sharedScope);
				scope.setParentScope(null);

				ScriptableObject.putProperty(scope, "config", Context.javaToJS(_config, scope));
				ScriptableObject.putProperty(scope, "request", Context.javaToJS(request, scope));
				ScriptableObject.putProperty(scope, "connection", Context.javaToJS(connection, scope));
				ScriptableObject.putProperty(scope, "arguments", Context.javaToJS(arguments, scope));
				ScriptableObject.putProperty(scope, "context", Context.javaToJS(context, scope));

				ret = cx.evaluateString(scope, _expr, "<cmd>", 1, null);
			} finally {
				Context.exit();
			}

			// 链式执行
			if (_next == null) {
				return ret;
			} else {
				context.put(_key, ret);
				return _next.execute(request, connection, arguments, context);
			}
		}
	}
}